package controllers;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import jxl.write.WriteException;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import controllers.CRUD.ObjectType;
import dtos.OrganizacionDto;
import models.ArcadiaLog;
import models.Arcadiano;
import models.ArcadianoNivel;
import models.Auditoria;
import models.ContactoEmpresa;
import models.Evento;
import models.HistorialContactoCargo;
import models.Invitacion;
import models.Localidad;
import models.Organizacion;
import models.Orquesta;
import models.Pais;
import models.Periodicidad;
import models.Provincia;
import models.SubBase;
import models.TipoEvento;
import play.data.binding.Binder;
import play.db.Model;
import play.db.jpa.JPA;
import play.exceptions.TemplateNotFoundException;
import play.mvc.With;
import utils.ColumnFilters;
import utils.ArcadiaConstants.TIPO_ENTIDAD;
import utils.ArcadiaConstants.TIPO_PERSONA;

@With(Secure.class)
public class Eventos extends ArcadiaCRUD {

	public static void updateInvitacion(String id, String invitacionId, String confirmacion, String asistencia, String acompaniante, String comentario) {
		String[] result = new String[2];
		if (invitacionId!=null) {
			Invitacion invitacion = Invitacion.findById(new Long(invitacionId));
			if (invitacion!=null){
				invitacion.acompaniantes = acompaniante;
				invitacion.confirmacion = Boolean.parseBoolean(confirmacion);
				invitacion.asistencia = Boolean.parseBoolean(asistencia);
				invitacion.observaciones = comentario;
				invitacion._save();
				result[0] = "OK";
			} else {
				result[0] = "ERROR";
				result[1] = "No se encuentra la invitacion que intenta modificar.";
			}
		} else {
			result[0] = "ERROR";
			result[1] = "No se encuentra la invitacion que intenta modificar.";
		}
		renderJSON(result);
	}
	
	public static void removeInvitacion(String id, String invitacionId) throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		Model object = type.findById(id);
		notFoundIfNull(object);
		Evento evento = (Evento)object;
		Invitacion remove = null;
		if (invitacionId!=null) {
			for (Invitacion invitacion: evento.invitaciones){
				if (invitacion.id.toString().equals(invitacionId)){
					remove = invitacion;
				}
			}
		}
		if (remove!=null){
			evento.removeInvitacion(remove);
			ArcadiaLog log = new ArcadiaLog();
			log.entidad = TIPO_ENTIDAD.EVENTO;
			log.idEntidad = new Long(object._key().toString());
			log.fecha = new Date();
			log.user = Security.getConnected();
			log.descripcion = "Se elimina la invitación de: " + remove.organizacion.toString();
			log._save();
			evento.lastLogs = log;
			evento._save();
			remove._delete();
		}
		
		redirect(request.controller + ".show", object._key());
	}
	
	public static void exportarAuspiciantes(String id) throws Exception {
		Evento evento = Evento.findById(new Long(id));
		
		List<OrganizacionDto> results = SubBases.getExportResult(evento.auspiciantes.organizaciones);
		
		String temporalName = String.valueOf(System.currentTimeMillis());
		File file;
		try {
			Auditoria auditoria = new Auditoria();
			auditoria.descripcion = "Se exporta la sub-base: ".concat(evento.auspiciantes.nombre);
			auditoria.user = Security.getConnected();
			auditoria.fecha = new Date();
			auditoria.subbase = evento.auspiciantes;
			auditoria.registros = results.size();
			auditoria._save();
			ColumnFilters filters = new ColumnFilters();
			filters.EMPRESA_REPARTICION_TITLE = true;
			file = XLSExportHelper.write(temporalName, results, filters);
			String name = "subbase_".concat(evento.auspiciantes.nombre).concat(".xls");
			renderBinary(file, name);
		} catch (WriteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void exportarInvitaciones(String id) throws Exception {
		Evento evento = Evento.findById(new Long(id));
		
		List<Invitacion> invitaciones = evento.invitaciones;
		List<Organizacion> organizaciones = new ArrayList<Organizacion>();
		for (Invitacion invitacion: invitaciones){
			organizaciones.add(invitacion.organizacion);
		}
		
		List<OrganizacionDto> results = SubBases.getExportResult(organizaciones);
		
		String temporalName = String.valueOf(System.currentTimeMillis());
		File file;
		try {
			Auditoria auditoria = new Auditoria();
			auditoria.descripcion = "Se exporta la lista de invitaciones de : ".concat(evento.nombre);
			auditoria.user = Security.getConnected();
			auditoria.fecha = new Date();
			auditoria.subbase = null;
			auditoria.registros = results.size();
			auditoria._save();
			ColumnFilters filters = new ColumnFilters();
			filters.EMPRESA_REPARTICION_TITLE = true;
			file = XLSExportHelper.write(temporalName, results, filters);
			String name = "invitaciones_".concat(evento.nombre).concat(".xls");
			renderBinary(file, name);
		} catch (WriteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void blank() throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		Constructor<?> constructor = type.entityClass.getDeclaredConstructor();
		constructor.setAccessible(true);
		Model object = (Model) constructor.newInstance();
		try {
			// start localidad initialization
			List<Pais> paises = Pais.findAll();
			Object paisSelected = Paises.getArgentina();
			List<Provincia> provincias = Provincias.getProvincias(paisSelected.toString());
			Object provinciaSelected = Provincias.getSantaFe(provincias);
			List<Localidad> localidades = Localidades.getLocalidades(provinciaSelected.toString());
			((Evento) object).localidad = Localidades.getSantaFe(localidades);
			// end localidad initialization
			
			// start TipoEventos initialization
			List<TipoEvento> tipoEventos = TipoEvento.findAll();			
			// end TipoEventos initialization
			
			// start Periodicidad initialization
			List<Periodicidad> periodicidades = Periodicidad.findAll();			
			// end Periodicidad initialization
			
			// start Orquesta initialization
			Orquesta orquesta = ((Evento)object).orquesta;
			if (orquesta == null)
				orquesta = new Orquesta();
			// start Orquesta initialization
			
			// start cliente initialization
			List<Organizacion> clientes = Organizacion.all().fetch(20);
			// end cliente initialization
						
			render(type, object, paises, provincias, localidades, paisSelected, provinciaSelected, tipoEventos, orquesta, periodicidades, clientes);
		} catch (TemplateNotFoundException e) {
			render("CRUD/blank.html", type, object);
		}
	}

	public static void create() throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		Constructor<?> constructor = type.entityClass.getDeclaredConstructor();
		constructor.setAccessible(true);
		Model object = (Model) constructor.newInstance();

		Binder.bindBean(params.getRootParamNode(), "object", object);

		validation.valid(object);
		
		if (validation.hasErrors()) {
			renderArgs.put("error", play.i18n.Messages.get("crud.hasErrors"));
			try {
				render(request.controller.replace(".", "/") + "/blank.html", type, object);

			} catch (TemplateNotFoundException e) {
				render("CRUD/blank.html", type, object);
			}
		}
		
		Orquesta orquestaToRemove = null;
		if (((Evento)object).orquestar){
			String hoteleria = params.get("orquesta.hoteleria");
			String traslado = params.get("orquesta.traslado");
			String paquete = params.get("orquesta.paquete");
			String pasaje = params.get("orquesta.pasaje");
			String prensa = params.get("orquesta.prensa");
			String catering = params.get("orquesta.catering");
			String decoracion = params.get("orquesta.decoracion");
			String fotografia = params.get("orquesta.fotografia");
			String video = params.get("orquesta.video");
			String observaciones = params.get("orquesta.observaciones");
			Orquesta orquesta = ((Evento)object).orquesta;
			if (orquesta == null){
				orquesta = new Orquesta();
				((Evento)object).orquesta = orquesta;
			}
				
			orquesta.hoteleria = hoteleria;
			orquesta.traslado = traslado;
			orquesta.paquete = paquete;
			orquesta.pasaje = pasaje;
			orquesta.prensa = prensa;
			orquesta.catering = catering;
			orquesta.decoracion = decoracion;
			orquesta.fotografia = fotografia;
			orquesta.video = video;
			orquesta.observaciones = observaciones;
			orquesta._save();
		} else {
			orquestaToRemove = ((Evento)object).orquesta;
			
			((Evento)object).orquesta = null;
		}
		
		object._save();
		
		if (orquestaToRemove!=null)
			orquestaToRemove._delete();
		
		ArcadiaLog log = new ArcadiaLog();
		log.entidad = TIPO_ENTIDAD.EVENTO;
		log.idEntidad = new Long(object._key().toString());
		log.fecha = new Date();
		log.user = Security.getConnected();
		log.descripcion = "Creación del Evento";
		log._save();
		((Evento) object).lastLogs = log;
		object._save();
		flash.success(play.i18n.Messages.get("crud.created", type.modelName));

		redirect(request.controller + ".show", object._key());
	}

	public static void save(String id) throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		Model object = type.findById(id);
		notFoundIfNull(object);
		Binder.bindBean(params.getRootParamNode(), "object", object);

		validation.valid(object);
		if (validation.hasErrors()) {
			flash.error("error", play.i18n.Messages.get("crud.hasErrors"));
			try {
				redirect(request.controller + ".show", object._key());
			} catch (TemplateNotFoundException e) {
				render("CRUD/show.html", type, object);
			}
		}
		ArcadiaLog log = new ArcadiaLog();
		log.entidad = TIPO_ENTIDAD.EVENTO;
		log.idEntidad = new Long(object._key().toString());
		log.fecha = new Date();
		log.user = Security.getConnected();
		log.descripcion = "Modificación de datos del Evento";
		log._save();
		((Evento) object).lastLogs = log;
		
		Orquesta orquestaToRemove = null;
		if (((Evento)object).orquestar){
			String hoteleria = params.get("orquesta.hoteleria");
			String traslado = params.get("orquesta.traslado");
			String paquete = params.get("orquesta.paquete");
			String pasaje = params.get("orquesta.pasaje");
			String prensa = params.get("orquesta.prensa");
			String catering = params.get("orquesta.catering");
			String decoracion = params.get("orquesta.decoracion");
			String fotografia = params.get("orquesta.fotografia");
			String video = params.get("orquesta.video");
			String observaciones = params.get("orquesta.observaciones");
			Orquesta orquesta = ((Evento)object).orquesta;
			if (orquesta == null){
				orquesta = new Orquesta();
				((Evento)object).orquesta = orquesta;
			}
				
			orquesta.hoteleria = hoteleria;
			orquesta.traslado = traslado;
			orquesta.paquete = paquete;
			orquesta.pasaje = pasaje;
			orquesta.prensa = prensa;
			orquesta.catering = catering;
			orquesta.decoracion = decoracion;
			orquesta.fotografia = fotografia;
			orquesta.video = video;
			orquesta.observaciones = observaciones;
			orquesta._save();
		} else {
			orquestaToRemove = ((Evento)object).orquesta;
			
			((Evento)object).orquesta = null;
		}
		
		object._save();
		
		if (orquestaToRemove!=null)
			orquestaToRemove._delete();
		
		flash.success(play.i18n.Messages.get("crud.saved", type.modelName));

		redirect(request.controller + ".show", object._key());
	}

	public static void show(String id) throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		Model object = type.findById(id);
		notFoundIfNull(object);
		try {
			// start localidad initialization
			Localidad localidad = ((Evento) object).localidad;
			List<Pais> paises = Pais.findAll();
			List<Provincia> provincias = null;
			List<Localidad> localidades = null;
			Object provinciaSelected = null;
			Object paisSelected = null;
			if (localidad != null) {
				provinciaSelected = localidad.provincia._key();
				paisSelected = localidad.provincia.pais._key();
				provincias = Provincias.getProvincias(paisSelected.toString());
				localidades = Localidades.getLocalidades(provinciaSelected.toString());
			} else {
				paisSelected = Paises.getArgentina();
				provincias = Provincias.getProvincias(paisSelected.toString());
				provinciaSelected = Provincias.getSantaFe(provincias);
				localidades = Localidades.getLocalidades(provinciaSelected.toString());
				((Evento) object).localidad = Localidades.getSantaFe(localidades);
			}
			// end localidad initialization

			// start TipoEventos initialization
			List<TipoEvento> tipoEventos = TipoEvento.findAll();			
			// end TipoEventos initialization
			
			// start Periodicidad initialization
			List<Periodicidad> periodicidades = Periodicidad.findAll();			
			// end Periodicidad initialization
						
			// start Orquesta initialization
			Orquesta orquesta = ((Evento)object).orquesta;
			if (orquesta == null)
				orquesta = new Orquesta();
			// start Orquesta initialization
			
			// start obtener arcadianos asociados
			List<ArcadianoNivel> arcadianosEvento = orderArcadianoNivel(((Evento) object).arcadianos);
			int lastArcadiano = ((Evento) object).arcadianos.size();
			List<Arcadiano> arcadianos = Arcadiano.findAll();
			// end obtener arcadianos asociados y no asociados
			
			// start cliente initialization
			List<Organizacion> clientes = Organizacion.all().fetch(20);
			// end cliente initialization
			
			// start cliente initialization
			List<SubBase> subbases = SubBase.findAll();
			// end cliente initialization
						
			render(type, object, paises, provincias, localidades, paisSelected, provinciaSelected, tipoEventos, orquesta, periodicidades,
					arcadianosEvento, lastArcadiano, arcadianos, clientes, subbases);
		} catch (TemplateNotFoundException e) {
			render("CRUD/show.html", type, object);
		}
	}
	
	public static void newArcadiano(String id, String nombre){
		String[] result = new String[2];
		Evento evento = Evento.findById(new Long(id));
		if (evento != null){
			Arcadiano arcadiano = new Arcadiano();
			arcadiano.nombre = nombre;
			arcadiano._save();
			
			try {
				auxiliarAsociarArcadiano(evento, arcadiano);
				result[0] = "OK";
			} catch (Exception e) {
				result[0] = "ERROR";
				result[1] = "No se puede crear el nuevo arcadiano";
			}
		} else {
			result[0] = "ERROR";
			result[1] = "No se puede crear el nuevo arcadiano";			
		}
		renderJSON(result);
	}
	
	private static void auxiliarAsociarArcadiano(Evento evento, Arcadiano arcadiano) throws Exception {
			ArcadianoNivel arcadianoNivel = new ArcadianoNivel();
			arcadianoNivel.arcadiano = arcadiano;
			arcadianoNivel.level = evento.arcadianos.size() + 1;
			arcadianoNivel._save();
			evento.asociarArcadiano(arcadianoNivel);

			ArcadiaLog log = new ArcadiaLog();
			log.entidad = TIPO_ENTIDAD.EVENTO;
			log.idEntidad = new Long(evento._key().toString());
			log.fecha = new Date();
			log.user = Security.getConnected();
			log.descripcion =  "Se agrega responsabilidad de Arcadiano ".concat(arcadiano.toString());
			log._save();
			evento.lastLogs=log;
			evento._save();		
			
	}
	
	public static void asociarArcadiano(String id, String arcadianoid) throws Exception {
		Evento evento = null;
		try {
			evento = Evento.findById(new Long(id));
			if (evento.getArcadiano(new Long(arcadianoid)) == null) {
				Arcadiano arcadiano = Arcadiano.findById(new Long(arcadianoid));
				auxiliarAsociarArcadiano(evento, arcadiano);
			}

			redirect(request.controller + ".show", evento._key());
		} catch (TemplateNotFoundException e) {
			redirect("Admin.index");
		}
	}

	public static void agregarAuspiciantes(String evento, String auspiciante) throws Exception {
		Evento eve = null;
		try {
			eve = Evento.findById(new Long(evento));
			if (eve != null) {
				SubBase subbase = SubBase.findById(new Long(auspiciante));
				eve.auspiciantes = subbase;
				
				ArcadiaLog log = new ArcadiaLog();
				log.entidad = TIPO_ENTIDAD.EVENTO;
				log.idEntidad = new Long(eve._key().toString());
				log.fecha = new Date();
				log.user = Security.getConnected();
				log.descripcion =  "Se agregan los auspiciantes. Sub-base: ".concat(subbase.nombre);
				log._save();
				eve.lastLogs=log;
				eve._save();		
				
			}

			redirect(request.controller + ".show", eve._key());
		} catch (TemplateNotFoundException e) {
			redirect("Admin.index");
		}
	}
	
	public static void agregarInvitaciones(String evento, String invitaciones) throws Exception {
		Evento eve = null;
		try {
			eve = Evento.findById(new Long(evento));
			if (eve != null) {
				SubBase subbase = SubBase.findById(new Long(invitaciones));
				for (Organizacion organizacion: subbase.organizaciones){
					if (!eve.containsInvitacion(organizacion)){
						Invitacion invitacion = new Invitacion();
						invitacion.acompaniantes="";
						invitacion.asistencia=false;
						invitacion.confirmacion=false;
						invitacion.observaciones="";
						invitacion.organizacion = organizacion;
						invitacion._save();
						eve.addInvitacion(invitacion);
					}
				}
				
				ArcadiaLog log = new ArcadiaLog();
				log.entidad = TIPO_ENTIDAD.EVENTO;
				log.idEntidad = new Long(eve._key().toString());
				log.fecha = new Date();
				log.user = Security.getConnected();
				log.descripcion =  "Se agregan los invitaciones. Sub-base: ".concat(subbase.nombre);
				log._save();
				eve.lastLogs=log;
				eve._save();		
				
			}

			redirect(request.controller + ".show", eve._key());
		} catch (TemplateNotFoundException e) {
			redirect("Admin.index");
		}
	}
	
	
	public static void removeArcadiano(String id, String arcadianoid) throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		Model object = type.findById(id);
		notFoundIfNull(object);
		ArcadianoNivel arcadiano = ((Evento) object).getArcadiano(new Long(arcadianoid));
		int level = -1;
		if (arcadiano != null) {
			level = arcadiano.level;
			((Evento) object).removeArcadiano(arcadiano);

			ArcadiaLog log = new ArcadiaLog();
			log.entidad = TIPO_ENTIDAD.EVENTO;
			log.idEntidad = new Long(object._key().toString());
			log.fecha = new Date();
			log.user = Security.getConnected();
			log.descripcion = "Eliminación responsabilidad de Arcadiano ".concat(arcadiano.toString());
			log._save();
			((Evento) object).lastLogs=log;
			object._save();		

			arcadiano._delete();
			for (ArcadianoNivel nivel : ((Evento) object).arcadianos) {
				if (nivel.level > level) {
					nivel.level = nivel.level - 1;
					nivel._save();
				}
			}
		}
		redirect(request.controller + ".show", object._key());
	}
	
	public static void upLevel(String id, String arcadianoid) throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		Model object = type.findById(id);
		notFoundIfNull(object);

		ArcadianoNivel arcadiano = ((Evento) object).getArcadiano(new Long(arcadianoid));
		if (arcadiano != null && arcadiano.level > 1) {
			int cambiar = arcadiano.level;
			arcadiano.level = cambiar - 1;
			arcadiano._save();
			for (ArcadianoNivel nivel : ((Evento) object).arcadianos) {
				if (nivel.level == arcadiano.level && nivel.id != arcadiano.id) {
					nivel.level = cambiar;
					nivel._save();
				}
			}
		}

		redirect(request.controller + ".show", object._key());
	}

	public static void downLevel(String id, String arcadianoid) throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		Model object = type.findById(id);
		notFoundIfNull(object);

		ArcadianoNivel arcadiano = ((Evento) object).getArcadiano(new Long(arcadianoid));
		if (arcadiano != null && arcadiano.level < ((Evento) object).arcadianos.size()) {
			int cambiar = arcadiano.level;
			arcadiano.level = cambiar + 1;
			arcadiano._save();
			for (ArcadianoNivel nivel : ((Evento) object).arcadianos) {
				if (nivel.level == arcadiano.level && nivel.id != arcadiano.id) {
					nivel.level = cambiar;
					nivel._save();
				}
			}
		}

		redirect(request.controller + ".show", object._key());
	}
	
	private static List<ArcadianoNivel> orderArcadianoNivel(List<ArcadianoNivel> arcadianos) {
		Collections.sort(arcadianos, new Comparator() {

			public int compare(Object o1, Object o2) {
				ArcadianoNivel e1 = (ArcadianoNivel) o1;
				ArcadianoNivel e2 = (ArcadianoNivel) o2;
				return Integer.valueOf(e1.level).compareTo(Integer.valueOf(e2.level));
			}
		});
		return arcadianos;
	}
	
	public static void newCliente(String id, String razonSocial, String nombre, String apellido, String marcaComercial, String telefono, String email){
		String[] result = new String[3];
		try {
			Organizacion intermediario = new Organizacion();
			if (razonSocial==null || "".equals(razonSocial))
				intermediario.persona = TIPO_PERSONA.IDEAL;
			else
				intermediario.persona = TIPO_PERSONA.FISICA;
			intermediario.razonSocial = razonSocial;
			intermediario.nombre = nombre;
			intermediario.apellido = apellido;
			intermediario.marcaComercial = marcaComercial;
			intermediario.mail = email;
			intermediario.telefono = telefono;			
			intermediario._save();
			
			ArcadiaLog log = new ArcadiaLog();
			log.entidad = TIPO_ENTIDAD.EVENTO;
			log.idEntidad = new Long(intermediario._key().toString());
			log.fecha = new Date();
			log.user = Security.getConnected();
			log.descripcion = "Se crea como cliente de un evento";
			log._save();
			intermediario.lastLogs = log;
			intermediario._save();
			
			result[0] = "OK";
			result[1] = intermediario._key().toString();
			result[2] = intermediario.toString();
		} catch (Exception e ){
			result[0] = "ERROR";
			result[1] = "No se puede crear el nuevo contacto";
		}
		renderJSON(result);
	}
		
}
